home *** CD-ROM | disk | FTP | other *** search
/ Die Speccy' 97 / Die Speccy' 97.iso / amiga_system / the_aminet / comm / bbs / s342q07.lha / ctdl.c < prev    next >
C/C++ Source or Header  |  1995-09-05  |  55KB  |  2,263 lines

  1. /*
  2. *       ctdl.c
  3. *
  4. * Command-interpreter code for Citadel.
  5. */
  6. #include "ctdl.h"
  7. char QWKmain(void);
  8.  
  9. /* #define NEED_MSG_PEEKING */
  10. /* #define NEED_MSG_LIST */
  11. /*
  12. *       history
  13. *
  14. * 86Aug16 HAW  Kill history from file because of space problems.
  15. * 84May18 JLS/HAW Greeting modified for coherency.
  16. * 84Apr04 HAW  Upgrade to BDS 1.50a begun.
  17. * 83Mar08 CrT  Aide-special functions installed & tested...
  18. * 83Feb24 CrT/SB Menus rearranged.
  19. * 82Dec06 CrT  2.00 release.
  20. * 82Nov05 CrT  removed main() from room2.c and split into sub-fn()s
  21. */
  22. /*
  23. *       Contents
  24. *
  25. * doAide()    handles Aide-only       commands
  26. * doChat()    handles C(hat)    command
  27. * doEnter()   handles E(nter)   command
  28. * doForget()    handles Z(Forget room)  command
  29. * doGoto()    handles G(oto)    command
  30. * doHelp()    handles H(elp)    command
  31. * doKnown()   handles K(nown rooms)   command
  32. * doLogin()   handles L(ogin)   command
  33. * doLogout()    handles T(erminate)     command
  34. * doMeet()    handles M(eet) User command
  35. * doRead()    handles R(ead)    command
  36. * doRegular()   fanout for above commands
  37. * doSkip()    handles S(kip)    command
  38. * doSysop()   handles sysop-only      commands
  39. * doUngoto()    handles U(ngoto)  command
  40. * getCommand()    prints prompt and gets command char
  41. * greeting()    System-entry blurb etc
  42. * main()      has the central menu code
  43. */
  44. char   ExitToMsdos = FALSE;     /* True when time to bring system down  */
  45. int    exitValue = CRASH_EXIT;
  46. static char NoChatAtAll = FALSE;
  47. char   MeetDisabled;
  48. char   ConsolePassword;
  49. extern CONFIG     cfg;    /* The main variable to be saved      */
  50. extern aRoom      roomBuf;  /* Room buffer    */
  51. extern MessageBuffer    msgBuf; /* Message buffer   */
  52. extern MessageBuffer    tempMess; /* Message buffer   */
  53. extern logBuffer  logBuf; /* Person's log buffer    */
  54. extern logBuffer  logTmp; /* Person's log buffer    */
  55. extern rTable     *roomTab; /* Room index for RAM   */
  56. extern LogTable   *logTab;  /* Log  index for RAM   */
  57. extern struct floor *FloorTab;
  58. extern long       FDSectCount;  /* size of files in directory   */
  59. extern int    thisRoom; /* Current room   */
  60. extern SECTOR_ID  pulledMLoc; /* Loc of msg to be pulled    */
  61. extern MSG_NUMBER pulledMId;  /* Id of msg to be pulled   */
  62. extern char       *who_str;
  63. extern char       remoteSysop;
  64. extern char       onConsole;  /* Where IO is ...    */
  65. extern char       whichIO;  /* Where IO is ...    */
  66. extern char       outFlag;
  67. extern char       loggedIn; /* Are we logged in?    */
  68. extern char       echo;
  69. extern char       newCarrier; /* Just got carrier, hurrah!    */
  70. extern char       justLostCarrier;/* Boo, hiss!   */
  71. extern char       textDownload; /* flag   */
  72. extern char       haveCarrier;
  73. extern char       *baseRoom;
  74. extern char       heldMess;
  75. extern char       anyEcho;
  76. extern char       PrintBanner;
  77. extern int      acount;
  78. #define AUDIT   9000
  79. extern char     audit[AUDIT];
  80. /*
  81. * doAide()
  82. *
  83. * This function handles the aide-only menu.
  84. *
  85. * return FALSE to fall invisibly into default error msg.
  86. */
  87. char doAide(char moreYet, char first)
  88.   {
  89.   label oldName;
  90.   int  rm;
  91.   char chatStack;
  92.   char fname[100];
  93.   char *ValAide[] =
  94.     {
  95.     "Chat           ", "Delete empty rooms  ", "Edit room\n",
  96.     "Insert message ", "Kill room           ", "S\bNot available.\n",
  97.     "\b", " ", ""
  98.  
  99.     };
  100.   extern char *APrivateRoom;
  101.   extern SListBase Moderators;
  102.   if (roomBuf.rbflags.ISDIR == 1 && HalfSysop())
  103.   ExtraOption(ValAide, "Add File\n");
  104.   if (!aide)
  105.     {
  106.     PushBack('E');
  107.  
  108.     }
  109.   if (moreYet)   first = '\0';
  110.   if (first)     PushBack(first);
  111.  
  112.     SpecialMessage("Status:Aide Functions");
  113.  
  114.   RegisterThisMenu("aide.mnu", ValAide);
  115.   switch (GetMenuChar())
  116.     {
  117.     case 'A':
  118.     getString("EFILEN", fname, sizeof fname, 0);
  119.     if (access(fname, 0) != 0)
  120.       {
  121.       Output_Citadel_Message("NOSUCH",(long)fname,NULL,NULL);   /* no such file */
  122.       break;
  123.  
  124.       }
  125.     if (CopyFile(fname, &roomBuf))
  126.       {
  127.       FileCommentUpdate(fname, FALSE);
  128.  
  129.       }
  130.     break;
  131.     case '\b':
  132.     mPrintf("\b \b"); /* not sure why this is necessary */
  133.     return BACKED_OUT;
  134.     case 'C':
  135.     logMessage(TRIED_CHAT, "", 'C');
  136.     if (NoChatAtAll && !SomeSysop())
  137.       {
  138.       if (!MultiBanner("nochat"))
  139.       tutorial("nochat.blb", TRUE);
  140.  
  141.       }
  142.     else
  143.       {
  144.       chatStack = cfg.BoolFlags.noChat;
  145.       cfg.BoolFlags.noChat = FALSE;
  146.       if (whichIO == MODEM) ringSysop();
  147.       else      interact(TRUE) ;
  148.       cfg.BoolFlags.noChat = chatStack;
  149.  
  150.       }
  151.     break;
  152.     case 'D':
  153.     ZeroMsgBuffer(&msgBuf);
  154.     sPrintf(msgBuf.mbtext, "The following empty rooms deleted by %s: ",
  155.     logBuf.lbname);
  156.     if (!getYesNo("CONFRM"))
  157.     break;
  158.     strCpy(oldName, roomBuf.rbname);
  159.     indexRooms();
  160.     if ((rm=roomExists(oldName)) != ERROR)  getRoom(rm);
  161.     else          getRoom(LOBBY);
  162.     aideMessage(NULL, /* noteDeletedMessage== */ FALSE );
  163.     break;
  164.     case 'E':
  165.     renameRoom();
  166.     break;
  167.     case 'I':
  168.     ZeroMsgBuffer(&msgBuf);
  169.     if (
  170.     thisRoom   == AIDEROOM
  171.     ||
  172.     pulledMId  == 0l
  173.     )
  174.       {
  175.       Output_Citadel_Message("NOMSGI",NULL,NULL,NULL); /* no message insertable*/
  176.       break;
  177.  
  178.       }
  179.     if (!getYesNo("CONFRM"))
  180.     break;
  181.     noteAMessage(roomBuf.msg, MSGSPERRM, pulledMId, pulledMLoc);
  182.     putRoom(thisRoom);
  183.     noteRoom();
  184.     sPrintf(msgBuf.mbtext,"Following message inserted in %s> by %s",
  185.     formRoom(thisRoom, FALSE, FALSE), logBuf.lbname);
  186.     aideMessage(NULL, /* noteDeletedMessage == */ TRUE);
  187.     break;
  188.     case 'K':
  189.     if (
  190.     thisRoom == LOBBY
  191.     ||
  192.     thisRoom == MAILROOM
  193.     ||
  194.     thisRoom == AIDEROOM
  195.     )
  196.       {
  197.       Output_Citadel_Message("NOKILL",NULL,NULL,NULL);
  198.       break;
  199.  
  200.       }
  201.     if (!getYesNo("CONFRM"))   break;
  202.     ZeroMsgBuffer(&msgBuf);
  203.     sPrintf( msgBuf.mbtext, "%s> killed by %s",roomBuf.rbname,logBuf.lbname);
  204.     aideMessage(NULL, /* noteDeletedMessage == */ FALSE);
  205.     KillInfo(roomBuf.rbname);
  206.     roomBuf.rbflags.INUSE = FALSE;
  207.     putRoom(thisRoom);
  208.     noteRoom();
  209.     getRoom(LOBBY);
  210.     break;
  211.     case 'S':
  212.     #ifdef NEED_AVAILABLE
  213.     changeDate();
  214.     #endif
  215.     break;
  216.  
  217.     }
  218.   return GOOD_SELECT;
  219.  
  220.   }
  221. /*
  222. * doChat()
  223. *
  224. * Chatting!
  225. */
  226. char doChat(char moreYet, char first)
  227.   {
  228.   if (moreYet)   first = '\0';
  229.   if (first)     oChar(first);
  230.   if (whichIO != MODEM)
  231.     {
  232.     interact(TRUE) ;
  233.     if (whichIO == CONSOLE)
  234.     if (getYesNo("MODEMM"))
  235.       {
  236.       whichIO = MODEM;
  237.       setUp(FALSE);
  238.       if (!gotCarrier()) EnableModem(FALSE);
  239.  
  240.       }
  241.  
  242.     }
  243.   else
  244.     {
  245.     logMessage(TRIED_CHAT, "", 'C');
  246.     if (cfg.BoolFlags.noChat)
  247.       {
  248.       if (!MultiBanner("nochat"))
  249.       tutorial("nochat.blb", TRUE);
  250.       return GOOD_SELECT;
  251.  
  252.       }
  253.     ringSysop();
  254.  
  255.     }
  256.   return GOOD_SELECT;
  257.  
  258.   }
  259. /*
  260. * doEnter()
  261. *
  262. * This function handles the E(nter) command.
  263. */
  264. char doEnter(char moreYet, char first)
  265.   {
  266.   #define CONFIGURATION   0
  267.   #define MESSAGE   1
  268.   #define PASSWORD  2
  269.   #define ROOM    3
  270.   #define ENTERFILE       4
  271.   #define CONTINUED       5
  272.   #define NETWORK   6
  273.   #define DEFAULT_MESSAGE 7
  274.   char what;      /* one of above seven */
  275.   SListBase  ESelects =
  276.     {
  277.     NULL, FindSelect, NULL, NoFree, NULL
  278.  
  279.     };
  280.   char *EnterOpts[] =
  281.     {
  282.     TERM "\r", TERM "\n", NTERM "Xmodem", NTERM "Ymodem",
  283.     #ifdef WXMODEM_AVAILABLE
  284.     NTERM "Wxmodem",
  285.     #endif
  286.     TERM "Configuration", TERM "Message", TERM "Password",
  287.     TERM "Room", TERM "Held Message", TERM "Net-Message",
  288.     /* These are for external protocols -- don't delete them! */
  289.     " ", " ", " ",
  290.     " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", ""
  291.  
  292.     };
  293.   char abort, Protocol, again;
  294.   char *letter, cmdbuf[30];
  295.   if (loggedIn && roomBuf.rbflags.ISDIR == 1)
  296.   ExtraOption(EnterOpts, TERM "F");
  297.   AddExternProtocolOptions(EnterOpts, TRUE);
  298.   if (moreYet)   first = '\0';
  299.   abort       = FALSE  ;
  300.   if (thisRoom != MAILROOM && !loggedIn &&
  301.   !cfg.BoolFlags.unlogEnterOk)
  302.     {
  303.     Output_Citadel_Message("ENTERM",NULL,NULL,NULL);
  304.     return GOOD_SELECT;
  305.  
  306.     }
  307.   SpecialMessage("Status:Enter");
  308.   if (first)     PushBack(first);
  309.   do
  310.     {
  311.     again = FALSE;
  312.     outFlag = OUTOK;
  313.     Protocol  = ASCII  ;
  314.     what  = DEFAULT_MESSAGE;
  315.     if (CmdMenuList(EnterOpts, &ESelects, "entopt.mnu", cmdbuf,
  316.     moreYet, TRUE) == BACKED_OUT)
  317.     return BACKED_OUT;
  318.     letter = cmdbuf;
  319.     do
  320.       {
  321.       switch (*letter)
  322.         {
  323.         case '\r':
  324.         case '\n':
  325.         break;
  326.         #ifdef WXMODEM_AVAILABLE
  327.         case 'X':
  328.         case 'Y':
  329.         case 'W':
  330.         Protocol = (*letter == 'Y') ? YMDM : (*letter == 'X') ? XMDM : WXMDM;
  331.         break;
  332.         #else
  333.         case 'X':
  334.         case 'Y':
  335.         Protocol = (*letter == 'Y') ? YMDM : XMDM;
  336.         break;
  337.         #endif
  338.         case 'F':
  339.         if (Protocol == ASCII)
  340.           {
  341.           mPrintf("\b\bXmodem F ");
  342.           Protocol = XMDM;
  343.  
  344.           }
  345.         mPrintf("\bile Upload ");
  346.         if (!roomBuf.rbflags.UPLOAD || logBuf.lbflags.TWIT)
  347.           {
  348.           Output_Citadel_Message("NOUPLD",NULL,NULL,NULL);
  349.           abort = TRUE;
  350.  
  351.           }
  352.         what    = ENTERFILE;
  353.         break;
  354.         case 'C':
  355.         again = reconfigure();
  356.         what  = CONFIGURATION;
  357.         break;
  358.         case 'M':
  359.         what  = MESSAGE;
  360.         break;
  361.         case 'P':
  362.         what  = PASSWORD     ;
  363.         break;
  364.         case 'R':
  365.         if (!cfg.BoolFlags.nonAideRoomOk && !aide)
  366.           {
  367.           Output_Citadel_Message("NOTAID",NULL,NULL,NULL);
  368.           abort   = TRUE;
  369.           break;
  370.  
  371.           }
  372.         if (!loggedIn)
  373.           {
  374.           Output_Citadel_Message("LGICRR",NULL,NULL,NULL);
  375.           abort = TRUE;
  376.           break;
  377.  
  378.           }
  379.         if (logBuf.lbflags.TWIT)
  380.           {
  381.           Output_Citadel_Message("TWITNR",NULL,NULL,NULL);
  382.           abort = TRUE;
  383.           break;
  384.  
  385.           }
  386.         what  = ROOM;
  387.         break;
  388.         case 'H':
  389.         what = CONTINUED;
  390.         Protocol   = ASCII; /* can't do this using protocol */
  391.         break;
  392.         case 'N':
  393.         if( logBuf.lbflags.NET_PRIVS )
  394.           what = NETWORK;
  395.         else Output_Citadel_Message("NONETP",NULL, NULL, NULL);
  396.         break;
  397.         default:
  398.         if ((Protocol = FindProtocolCode(*letter, TRUE)) == -1)
  399.         abort = TRUE;
  400.  
  401.         }
  402.       ++letter;
  403.  
  404.       }
  405.     while (moreYet && !abort && *letter);
  406.  
  407.     }
  408.   while (again);
  409.   KillList(&ESelects);
  410.   doCR();
  411.   if (!abort)
  412.     {
  413.     if (whichIO != CONSOLE && loggedIn &&
  414.     (thisRoom == MAILROOM || roomTab[thisRoom].rtflags.ANON))
  415.     echo = CALLER;
  416.     switch (what)
  417.       {
  418.       case DEFAULT_MESSAGE:
  419.       if (Protocol != ASCII)
  420.         {
  421.         Output_Citadel_Message("MSGTRN",NULL,NULL,NULL);
  422.         }
  423.       case   MESSAGE:   makeMessage(Protocol);  break;
  424.       case  PASSWORD:   newPW()   ; break;
  425.       case      ROOM:   makeRoom()    ; break;
  426.       case ENTERFILE:   upLoad(Protocol,NULL,TRUE)  ; break;
  427.       case CONTINUED:   hldMessage(FALSE) ; break;
  428.       case   NETWORK:   netMessage(Protocol); break;
  429.  
  430.       }
  431.     echo = BOTH;
  432.  
  433.     }
  434.   return GOOD_SELECT ;
  435.  
  436.   }
  437. /*
  438. * doForget()
  439. *
  440. * This function handles the (Forget room) command.
  441. */
  442. char doForget(char expand)
  443.   {
  444.   if (!expand)
  445.     {
  446.     mPrintf("%s\n ", roomBuf.rbname);
  447.     if (thisRoom == LOBBY    ||
  448.     thisRoom == MAILROOM ||
  449.     thisRoom == AIDEROOM)
  450.       {
  451.       Output_Citadel_Message("CANTFG",NULL,NULL,NULL);
  452.       return GOOD_SELECT ;
  453.  
  454.       }
  455.     if (!getYesNo("CONFRM"))   return GOOD_SELECT;
  456.     SetKnown(FORGET_OFFSET, 0, thisRoom, &logBuf);
  457.     gotoRoom(baseRoom, 'S');
  458.  
  459.     }
  460.   else
  461.     {
  462.     /* mPrintf("\b\b "); */
  463.     listRooms(FORGOTTEN);
  464.  
  465.     }
  466.   return GOOD_SELECT;
  467.  
  468.   }
  469. /*
  470. * doGoto()
  471. *
  472. * This function handles the G(oto) command.
  473. */
  474. char doGoto(char expand)
  475.   {
  476.   label roomName;
  477.   int   oldRoom;
  478.   outFlag = IMPERVIOUS;
  479.   if (!expand)
  480.     {
  481.     oldRoom = thisRoom;
  482.     gotoRoom("", 'R');
  483.     if (oldRoom == thisRoom && loggedIn && !expert)
  484.     Output_Citadel_Message("NOMMSG",NULL,NULL,NULL);
  485.     return GOOD_SELECT;
  486.  
  487.     }
  488.   if (getNormStr("", roomName, NAMESIZE, BS_VALID) == BACKED_OUT)
  489.     {
  490.     return BACKED_OUT;
  491.  
  492.     }
  493.   if (roomName[0] == '?')
  494.     {
  495.     listRooms(NOT_INTRO);
  496.  
  497.     }
  498.   else
  499.   gotoRoom(roomName, 'R');
  500.   return GOOD_SELECT;
  501.  
  502.   }
  503. /*
  504. * doHelp()
  505. *
  506. * This function the handles the H(elp) command.
  507. */
  508. char doHelp(char expand)
  509.   {
  510.   label fileName;
  511.  
  512.   SpecialMessage("Status:Help");
  513.  
  514.   if (!expand)
  515.     {
  516.     mPrintf("\n\n");
  517.     printHelp("mainhelp.hlp");
  518.     return GOOD_SELECT;
  519.  
  520.     }
  521.   if (getNormStr("", fileName, (sizeof fileName) - 4, BS_VALID) == BACKED_OUT)
  522.   return BACKED_OUT;
  523.   if (strLen(fileName) == 0)
  524.   strCpy(fileName, "mainhelp");
  525.   if (fileName[0] == '?')     printHelp("helpopt.hlp");
  526.   else
  527.     {
  528.     /* adding the extention makes things look simpler for   */
  529.     /* the user... and restricts the files which can be read  */
  530.     strCat(fileName, ".hlp");
  531.     printHelp(fileName);
  532.  
  533.     }
  534.   return GOOD_SELECT;
  535.  
  536.   }
  537. /*
  538. * doKnown()
  539. *
  540. * This function handles the K(nown rooms) command.
  541. */
  542. char doKnown(char expand)
  543.   {
  544.   char select = ERROR, c[2], again;
  545.   label matchstr;
  546.   char *KMenuOpts[] =
  547.     {
  548.     TERM "Anonymous rooms\n", TERM "Match", TERM "Directory rooms\n",
  549.     TERM "Shared rooms\n", TERM "Private rooms\n",
  550.     TERM "Z\bForgotten rooms\n", TERM "Information", TERM "Read-only\n",
  551.     TERM "\r", TERM "\n", ""
  552.  
  553.     };
  554.   SListBase  KSelects =
  555.     {
  556.     NULL, FindSelect, NULL, NoFree, NULL
  557.  
  558.     };
  559.  
  560.   SpecialMessage("Status:Known");
  561.  
  562.   if (!expand)
  563.     {
  564.     mPrintf("\n ");
  565.     listRooms(NOT_INTRO);
  566.  
  567.     }
  568.   else
  569.     {
  570.     do
  571.       {
  572.       again = FALSE;
  573.       if (CmdMenuList(KMenuOpts, &KSelects, "known.mnu", c, TRUE, TRUE)
  574.       == BACKED_OUT)
  575.       return BACKED_OUT;
  576.       switch (c[0])
  577.         {
  578.         case 'I':
  579.         AllInfo();
  580.         break;
  581.         case 'A':
  582.         select = ANON_SEL;
  583.         break;
  584.         case 'M':
  585.         if (getNormStr("",matchstr,NAMESIZE, BS_VALID) == BACKED_OUT)
  586.           {
  587.           again = TRUE;
  588.           select = ERROR;
  589.           PushBack('\b');
  590.           oChar(' ');
  591.  
  592.           }
  593.         else select = MATCH_SEL;
  594.         break;
  595.         case 'D':
  596.         select = DR_SEL;
  597.         break;
  598.         case 'S':
  599.         select = SH_SEL;
  600.         break;
  601.         case 'P':
  602.         select = PR_SEL;
  603.         break;
  604.         case 'Z':
  605.         select = FORGOTTEN;
  606.         break;
  607.         case 'R':
  608.         select = READONLY;
  609.         break;
  610.         case '\r':
  611.         doCR();
  612.         case '\n':
  613.         strCpy(matchstr, "");
  614.         select = MATCH_SEL;
  615.         break;
  616.  
  617.         }
  618.       if (select != MATCH_SEL && select != ERROR)
  619.       listRooms(select);
  620.       else if (select != ERROR)
  621.       searchRooms(matchstr);
  622.  
  623.       }
  624.     while (again);
  625.  
  626.     }
  627.   KillList(&KSelects);
  628.   return GOOD_SELECT;
  629.  
  630.   }
  631. /*
  632. * doLogin()
  633. *
  634. * This function handles the L(ogin) command.
  635. */
  636. char doLogin(char moreYet)
  637.   {
  638.   label passWord;
  639.   if (!moreYet)   mPrintf("\n");
  640.  
  641.   SpecialMessage("Status:Login");
  642.  
  643.   if (loggedIn)
  644.     {
  645.     Output_Citadel_Message("ALRULG",NULL,NULL,NULL);
  646.     return GOOD_SELECT;
  647.  
  648.     }
  649.   echo  = CALLER;
  650.   if (getNormStr(moreYet ? "" : "ULGPWD",
  651.   passWord, NAMESIZE, (moreYet) ? BS_VALID : NO_ECHO) ==
  652.   BACKED_OUT)
  653.     {
  654.     return BACKED_OUT;
  655.  
  656.     }
  657.   echo  = BOTH;
  658.   login(passWord);
  659.   return GOOD_SELECT;
  660.  
  661.   }
  662. /*
  663. * doLogout()
  664. *
  665. * This function handles the T(erminate) command.
  666. */
  667. char doLogout(char expand, char first)
  668.   {
  669.   char cx;
  670.  
  671.   SpecialMessage("Status:Terminating");
  672.  
  673.   if (expand)   first = '\0';
  674.   outFlag = IMPERVIOUS;
  675.   if (heldMess && !cfg.BoolFlags.HoldOnLost)
  676.     {
  677.     Output_Citadel_Message("HOLDMS",NULL,NULL,NULL);
  678.     mAbort(); /* clear any first-run input fromuser */
  679.  
  680.     }
  681.   if (first)   oChar(first);
  682.   if( first )
  683.     {
  684.     cx = first;
  685.  
  686.     }
  687.   else cx = iChar();
  688.   switch (toUpper( cx ))
  689.     {
  690.     case '\b':
  691.     if (expand) return BACKED_OUT;
  692.     default:
  693.     Output_Citadel_Message("LGOPTS",NULL,NULL,NULL);
  694.     break;
  695.     case 'Q':
  696.     mPrintf("uit-also\n ");
  697.     if (!expand)
  698.       {
  699.       if (!getYesNo("CONFRM"))   break;
  700.  
  701.       }
  702.     if (!onLine()) break;
  703.     terminate( /* hangUp == */ TRUE, TRUE);
  704.     break;
  705.     case 'S':
  706.     mPrintf("tay\n ");
  707.     terminate( /* hangUp == */ FALSE, TRUE);
  708.     break;
  709.     case 'A':
  710.     mPrintf("bort\n ");
  711.     terminate( /* hangUp == */ TRUE, FALSE);
  712.  
  713.     }
  714.   outFlag = OUTOK;
  715.   return GOOD_SELECT;
  716.  
  717.   }
  718. OptValues Opt;
  719. char revOrder;  /* Udderly HIDEOUS kludge.  MOOOOOO! */
  720. char PhraseUser;
  721. /*
  722. * doMeet()
  723. *
  724. * This function handles the M(eet) User command.
  725. */
  726. char doMeet(char moreYet)
  727.   {
  728.   label User;
  729.   int   logNo;
  730.  
  731.     SpecialMessage("Status:Meet Users");
  732.  
  733.   if (!moreYet) doCR();
  734.   if (getNormStr(moreYet ? "" : "USMEET",
  735.   User, NAMESIZE, QUEST_SPECIAL | BS_VALID) == BACKED_OUT)
  736.     {
  737.     return BACKED_OUT;
  738.  
  739.     }
  740.   if (strLen(User) != 0)
  741.     {
  742.     if (User[0] == '?')
  743.       {
  744.       BioDirectory();
  745.       return GOOD_SELECT;
  746.  
  747.       }
  748.     logNo = findPerson(User, &logTmp);
  749.     if (logNo == ERROR)
  750.       {
  751.       Output_Citadel_Message("NOPERS",(long)User,NULL,NULL);
  752.       }
  753.     else
  754.       {
  755.       if (GetBioInfo(logNo))
  756.         {
  757.         Output_Citadel_Message("BIOOFU",(long)logTmp.lbname,NULL,NULL);
  758.         doCR();
  759.         mPrintf("%s\n ", msgBuf.mbtext);
  760.  
  761.         }
  762.       else  Output_Citadel_Message("NOBIOU",(long)logTmp.lbname,NULL,NULL);
  763.       }
  764.  
  765.     }
  766.   return GOOD_SELECT;
  767.  
  768.   }
  769. /*
  770. * doRead()
  771. *
  772. * This function handles the R(ead) command.
  773. */
  774. static void *FindUser(char *element, int x);
  775. int   UserOptAdd(char *str);
  776. char doRead(char moreYet, char first)
  777.   {
  778.   char abort = FALSE,
  779.   Compressed = FALSE,
  780.   extDir,
  781.   doDir,
  782.   again,
  783.   hostFile,
  784.   whichMess,
  785.   status = FALSE,
  786.   SrchUser,
  787.   srchPhrase,
  788.   protocol,
  789.   global,
  790.   filestuff = FALSE,
  791.   ReadArchive;
  792.   char *letter, secondletter;
  793.   char fileName[100];
  794.   int    CurRoom;
  795.   extern FILE* upfd;
  796.   SListBase  RSelects =
  797.     {
  798.     NULL, FindSelect, NULL, NoFree, NULL
  799.  
  800.     };
  801.   SListBase  CSelects =
  802.     {
  803.     NULL, FindSelect, NULL, NoFree, NULL
  804.  
  805.     };
  806.   extern char journalMessage, FormatFlag;
  807.   extern int outPut;
  808.   char *ReadOpts[] =
  809.     {
  810.     TERM "\r", TERM "\n",
  811.     #ifdef NO_DeARC_SUPPORT
  812.     TERM "Archive-Directory(s)\n",
  813.     #else
  814.     TERM "Archive",
  815.     #endif
  816.     TERM "Forward", NTERM "Global", NTERM "Local-only", TERM "New",
  817.     TERM "Old-reverse", TERM "Reverse", TERM "Status\n", NTERM "Xmodem",
  818.     #ifdef WXMODEM_AVAILABLE
  819.     NTERM "Wxmodem",
  820.     #endif
  821.     NTERM "Ymodem", NTERM "User", NTERM "Phrase",
  822.     /* these two are here rather than optional due to .RGE/.RGD */
  823.     TERM "Directory", TERM "Extended-Directory", " ", " ", " ", " ",
  824.     " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ",
  825.     " ", " ", " ", " ", " ", ""
  826.  
  827.     };
  828.   #ifndef NO_DeARC_SUPPORT
  829.   char *CompOpts[] =
  830.     {
  831.     TERM "Directory(s)\n", TERM "File(s)\n", TERM "T\bFile(s)\n",
  832.     TERM "B\bFile(s)\n", TERM "\nDirectory(s)", ""
  833.  
  834.     };
  835.   #endif
  836.   char  cmdbuf[40];
  837.   whichMess = NEWoNLY;
  838.   if (moreYet)   first = '\0';
  839.   zero_struct(Opt);
  840.   Opt.Date = -1l;
  841.   InitListValues(&Opt.Users, FindUser, NULL, free, NULL);
  842.   if (thisRoom == MAILROOM && !loggedIn  &&
  843.   !cfg.BoolFlags.unlogReadOk)
  844.     {
  845.     showMessages(whichMess, revOrder,
  846.     logBuf.lbvisit[logBuf.lbgen[thisRoom] & CALLMASK],
  847.     OptionValidate);
  848.     return GOOD_SELECT;
  849.  
  850.     }
  851.   if (!loggedIn  &&  !cfg.BoolFlags.unlogReadOk)
  852.     {
  853.     Output_Citadel_Message("READMM",NULL,NULL,NULL);
  854.     return GOOD_SELECT;
  855.  
  856.     }
  857.   if (first)     PushBack(first);
  858.   if (roomBuf.rbflags.ISDIR == 1 && loggedIn && !logBuf.lbflags.TWIT)
  859.     {
  860.     ExtraOption(ReadOpts, TERM "Binary file(s)");
  861.     ExtraOption(ReadOpts, TERM "Textfile(s)");
  862.  
  863.     }
  864.   if (AnyCompression())
  865.   ExtraOption(ReadOpts, NTERM "Compressed");
  866.   AddExternProtocolOptions(ReadOpts, FALSE);
  867.   if (HalfSysop())
  868.   ExtraOption(ReadOpts, TERM "Invited-users");
  869.  
  870.   SpecialMessage("Status:Reading");
  871.  
  872.   do
  873.     {
  874.     again = FALSE;
  875.     protocol = ASCII;
  876.     whichMess = NEWoNLY;
  877.     extDir = doDir = hostFile = SrchUser = srchPhrase =
  878.     global = ReadArchive = PhraseUser = revOrder = FALSE;
  879.     if (CmdMenuList(ReadOpts, &RSelects, "readopt.mnu", cmdbuf, moreYet, TRUE) ==
  880.     BACKED_OUT)
  881.     return BACKED_OUT;
  882.     letter = cmdbuf;
  883.     do
  884.       {
  885.       outFlag = OUTOK;
  886.       switch (*letter)
  887.         {
  888.         case '\r':
  889.         doCR();
  890.         case '\n':
  891.         break;
  892.         case 'C':
  893.         Compressed = TRUE;
  894.         break;
  895.         case 'A':
  896.         if (   ( global || roomBuf.rbflags.ISDIR )
  897.             && ( logBuf.lbflags.DL_PRIVS || aide ) )
  898.           {
  899.           if (roomBuf.rbflags.DOWNLOAD || HalfSysop())
  900.             {
  901.             if (CmdMenuList(CompOpts, &CSelects, "", cmdbuf, TRUE,
  902.             FALSE) == BACKED_OUT)
  903.               {
  904.               again = TRUE;
  905.               PushBack('\b');
  906.  
  907.               }
  908.             else
  909.               {
  910.               switch (cmdbuf[0])
  911.                 {
  912.                 case '\n':
  913.                 case '\r':
  914.                 case 'D':
  915.                 ReadArchive = 1;
  916.                 break;
  917.                 case 'T':
  918.                 case 'B':
  919.                 case 'F':
  920.                 ReadArchive = 2;
  921.                 break;
  922.                 default:
  923.                 abort = TRUE;
  924.  
  925.                 }
  926.               break;
  927.  
  928.               }
  929.  
  930.             }
  931.           else
  932.             {
  933.             Output_Citadel_Message("NODLDS",NULL,NULL,NULL);
  934.             abort = TRUE;
  935.             break;
  936.  
  937.             }
  938.  
  939.           }
  940.         else
  941.           {
  942.           Output_Citadel_Message("NOTDIR",NULL,NULL,NULL);
  943.           abort = TRUE;
  944.           break;
  945.           };
  946.  
  947.         break;
  948.         case 'F':
  949.         revOrder    = FALSE;
  950.         whichMess   = OLDaNDnEW;
  951.         goto commondate;
  952.         case 'G':
  953.         global  = TRUE;
  954.         break;
  955.         case 'L':
  956.         Opt.LocalOnly = TRUE;
  957.         break;
  958.         case 'N':
  959.         whichMess   = NEWoNLY;
  960.         goto commondate;
  961.         case 'O':
  962.         revOrder    = TRUE;
  963.         whichMess   = OLDoNLY;
  964.         goto commondate;
  965.         case 'R':
  966.         revOrder    = TRUE;
  967.         whichMess   = OLDaNDnEW;
  968.         commondate:
  969.         if (moreYet)
  970.           {
  971.           if (getString("", fileName, NAMESIZE,
  972.           BS_VALID | QUEST_SPECIAL) == BACKED_OUT)
  973.             {
  974.             again = TRUE;
  975.             oChar(' ');
  976.             PushBack('\b');
  977.             break;
  978.  
  979.             }
  980.           if (fileName[0] == '?')
  981.             {
  982.             tutorial("readdate.blb", TRUE);
  983.             KillList(&RSelects);
  984.             return GOOD_SELECT;
  985.  
  986.             }
  987.           if (strLen(fileName) != 0)
  988.           if (ReadDate(fileName, &Opt.Date) == ERROR)
  989.             {
  990.             Output_Citadel_Message("INVLDD",NULL,NULL,NULL);
  991.             KillList(&RSelects);
  992.             return GOOD_SELECT;
  993.  
  994.             }
  995.  
  996.           }
  997.         else
  998.           {
  999.           doCR();
  1000.  
  1001.           }
  1002.         break;
  1003.         case 'S':
  1004.         status      = TRUE;
  1005.         break;
  1006.         #ifdef WXMODEM_AVAILABLE
  1007.         case 'X':
  1008.         case 'W':
  1009.         case 'Y':
  1010.         protocol    = (*letter == 'W') ? WXMDM :
  1011.         (*letter == 'X') ? XMDM : YMDM;
  1012.         break;
  1013.         #else
  1014.         case 'X':
  1015.         case 'Y':
  1016.         protocol    = (*letter == 'X') ? XMDM : YMDM;
  1017.         break;
  1018.         #endif
  1019.         case 'B':
  1020.         case 'T':
  1021.         filestuff = TRUE;
  1022.         case 'E':
  1023.         case 'D':
  1024.         if (!logBuf.lbflags.DL_PRIVS && !aide)
  1025.           {
  1026.           Output_Citadel_Message("NODLDP",NULL,NULL,NULL);
  1027.           abort = TRUE;
  1028.           break;
  1029.  
  1030.           }
  1031.         if (filestuff)
  1032.           {
  1033.           if (roomBuf.rbflags.DOWNLOAD == 1 || TheSysop() ||
  1034.           remoteSysop)
  1035.             {
  1036.             hostFile      = TRUE ;
  1037.             textDownload    = (*letter == 'T') ? TRUE : FALSE;
  1038.             if (textDownload && protocol == ASCII)
  1039.               {
  1040.               char cx;
  1041.               cx = modIn();
  1042.               switch (secondletter = toUpper(cx))
  1043.                 {
  1044.                 case '\b':
  1045.                 again = TRUE;
  1046.                 PushBack('\b');
  1047.                 break;
  1048.                 case 'F':
  1049.                 mPrintf("Formatted");
  1050.                 FormatFlag = TRUE;
  1051.                 break;
  1052.                 default:
  1053.                 PushBack(secondletter);
  1054.                 case '\r':
  1055.                 case '\n':
  1056.                 case ' ':
  1057.                 doCR();
  1058.  
  1059.                 }
  1060.  
  1061.               }
  1062.  
  1063.             }
  1064.           else
  1065.             {
  1066.             Output_Citadel_Message("NODLDS",NULL,NULL,NULL);
  1067.             abort = TRUE;
  1068.  
  1069.             }
  1070.  
  1071.           }
  1072.         else
  1073.           {
  1074.           if (roomBuf.rbflags.ISDIR == 1 || global)
  1075.             {
  1076.             if (global || roomBuf.rbflags.DOWNLOAD || TheSysop()
  1077.             || remoteSysop)
  1078.               {
  1079.               if (getNormStr("", fileName, sizeof fileName,
  1080.               BS_VALID) == BACKED_OUT)
  1081.                 {
  1082.                 PushBack('\b');
  1083.                 again = TRUE;
  1084.                 oChar(' ');
  1085.                 break;
  1086.  
  1087.                 }
  1088.               if (*letter == 'D') doDir   = TRUE;
  1089.               else      extDir  = TRUE;
  1090.               break;
  1091.  
  1092.               }
  1093.             else
  1094.               {
  1095.               Output_Citadel_Message("NODLDS",NULL,NULL,NULL);
  1096.               abort = TRUE;
  1097.               break;
  1098.  
  1099.               }
  1100.  
  1101.             }
  1102.           else
  1103.             {
  1104.             Output_Citadel_Message("NOTDIR",NULL,NULL,NULL);
  1105.             abort = TRUE;
  1106.  
  1107.             }
  1108.  
  1109.           }
  1110.         break;
  1111.         case 'I':
  1112.         if (doInviteDisplay() == BACKED_OUT)
  1113.           {
  1114.           PushBack('\b');
  1115.           again = TRUE;
  1116.           oChar(' ');
  1117.           break;
  1118.  
  1119.           }
  1120.         KillList(&RSelects);
  1121.         return  GOOD_SELECT;
  1122.         case 'P':
  1123.         srchPhrase = TRUE;
  1124.         PhraseUser = TRUE;
  1125.         break;
  1126.         case 'U':
  1127.         SrchUser = TRUE;
  1128.         PhraseUser = TRUE;
  1129.         break;
  1130.         default:
  1131.         if ((protocol = FindProtocolCode(*letter, FALSE)) == -1)
  1132.         abort = TRUE;
  1133.  
  1134.         }
  1135.       letter++;
  1136.  
  1137.       }
  1138.     while (moreYet && !abort && *letter);
  1139.  
  1140.     }
  1141.   while (again);
  1142.   KillList(&RSelects);
  1143.   KillList(&CSelects);
  1144.   if (abort) return GOOD_SELECT;
  1145.   if (status)
  1146.     {
  1147.     systat();
  1148.     return GOOD_SELECT;
  1149.  
  1150.     }
  1151.   if (ReadArchive)
  1152.     {
  1153.     #ifdef NO_DeARC_SUPPORT
  1154.     getNormStr("ARCHFN", fileName, sizeof fileName, 0);
  1155.     if (srchPhrase)
  1156.     getString("SEARCH", Opt.Phrase, PHRASE_SIZE, 0);
  1157.     mPrintf("\n %7s%8s%5s Name...\n ", "Crunched", "Normal", "date");
  1158.     wildCard(CompressedDir, fileName, TRUE, Opt.Phrase, TRUE);
  1159.     #else
  1160.     if (ReadArchive == 1)
  1161.       {
  1162.       getNormStr("ARCHFN", fileName, sizeof fileName, 0);
  1163.       if (srchPhrase)
  1164.       getString("SEARCH", Opt.Phrase, PHRASE_SIZE, 0);
  1165.       if (strchr(fileName, '.') == NULL) strCat(fileName, ".arc");
  1166.       wildCard(CompressedDir, fileName, TRUE, Opt.Phrase, TRUE);
  1167.  
  1168.       }
  1169.     else if (ReadArchive == 2)
  1170.     SendArcFiles(protocol);
  1171.     #endif
  1172.     return GOOD_SELECT;
  1173.  
  1174.     }
  1175.   if (doDir || extDir)
  1176.     {
  1177.     if (srchPhrase)
  1178.     getString("SEARCH", Opt.Phrase, PHRASE_SIZE, 0);
  1179.     if (!global)
  1180.     doDirectory(doDir, fileName, Opt.Phrase);
  1181.     else
  1182.       {
  1183.       CurRoom = thisRoom;
  1184.       /* should we have tableRunner() do this for us? */
  1185.       for (thisRoom = 0; outFlag == OUTOK && thisRoom < MAXROOMS;
  1186.       thisRoom++)
  1187.       if (roomTab[thisRoom].rtflags.INUSE &&
  1188.       roomTab[thisRoom].rtflags.ISDIR &&
  1189.       (roomTab[thisRoom].rtflags.DOWNLOAD || SomeSysop()) &&
  1190.       knowRoom(&logBuf, thisRoom) == KNOW_ROOM)
  1191.         {
  1192.         getRoom(thisRoom);
  1193.         mPrintf("\n (%s)\n ", roomBuf.rbname);
  1194.         doCR();   /* nice left side now */
  1195.         doDirectory(doDir, fileName, Opt.Phrase);
  1196.         if (outFlag == OUTNEXT) outFlag = OUTOK;
  1197.  
  1198.         }
  1199.       getRoom(CurRoom);
  1200.  
  1201.       }
  1202.     if (journalMessage)
  1203.       {
  1204.       if (redirect(NULL))
  1205.         {
  1206.         doDirectory(doDir, fileName, Opt.Phrase);
  1207.         undirect();
  1208.         /* fclose(upfd);
  1209.         outPut = NORMAL; */
  1210.  
  1211.         }
  1212.       journalMessage = FALSE;
  1213.  
  1214.       }
  1215.     return GOOD_SELECT;
  1216.  
  1217.     }
  1218.   if (hostFile)
  1219.     {
  1220.     if (srchPhrase)
  1221.     getString("SEARCH", Opt.Phrase, PHRASE_SIZE, 0);
  1222.     TranFiles(protocol, Opt.Phrase);
  1223.     FormatFlag = FALSE;
  1224.     return GOOD_SELECT;
  1225.  
  1226.     }
  1227.   if (SrchUser)
  1228.     {
  1229.     getList(UserOptAdd, "Users", NAMESIZE * 3, FALSE);
  1230.  
  1231.     }
  1232.   if (srchPhrase)
  1233.   getString("SEARCH", Opt.Phrase, PHRASE_SIZE, 0);
  1234.   if (Compressed)
  1235.     {
  1236.     if ((Compressed = GetUserCompression()) == NO_COMP)
  1237.     return GOOD_SELECT;
  1238.     doCR();
  1239.  
  1240.     }
  1241.   else Compressed = NO_COMP;
  1242.   download(whichMess, revOrder, protocol, global, Compressed);
  1243.   KillList(&Opt.Users);
  1244.   return GOOD_SELECT;
  1245.  
  1246.   }
  1247. /*
  1248. * UserOptAdd()
  1249. *
  1250. * This adds the given name to a list.
  1251. */
  1252. int UserOptAdd(char *str)
  1253.   {
  1254.   AddData(&Opt.Users, strdup(str), NULL, FALSE);
  1255.   return TRUE;
  1256.  
  1257.   }
  1258. /*
  1259. * FindUser()
  1260. *
  1261. * Is the current user @system _ domain going to match?
  1262. */
  1263. static void *FindUser(char *element, int x)
  1264. /* x is actually not used -- we use global msgBuf */
  1265.   {
  1266.   label User;
  1267.   char System[(2 * NAMESIZE) + 2];
  1268.   System[0] = 0;
  1269.   SepNameSystem(element, User, System, NULL);
  1270.   if (strLen(User) != 0 && matchString(msgBuf.mbauth, User,
  1271.   lbyte(msgBuf.mbauth)) == NULL)
  1272.     {
  1273.     if (strLen(msgBuf.mbto) == 0) return NULL;
  1274.     if (matchString(msgBuf.mbto, User, lbyte(msgBuf.mbto)) == NULL)
  1275.     return NULL;
  1276.  
  1277.     }
  1278.   if (strLen(System) != 0)
  1279.     {
  1280.     if (matchString(msgBuf.mboname, System, lbyte(msgBuf.mboname))
  1281.     == NULL &&
  1282.     matchString(msgBuf.mbdomain, System, lbyte(msgBuf.mbdomain)) == NULL)
  1283.     return NULL;
  1284.  
  1285.     }
  1286.   return element;
  1287.  
  1288.   }
  1289. /*
  1290. * OptionValidate()
  1291. *
  1292. * This is sent to showMessages.
  1293. */
  1294. char OptionValidate(int mode)
  1295.   {
  1296.   if (OptionCheck(mode))
  1297.     {
  1298.     printMessage(0);
  1299.     return Pause_Message_Check();
  1300.  
  1301.     }
  1302.   else mAbort();      /* give a chance to interrupt */
  1303.   return (char)( (mode == 1) ? TRUE : FALSE);
  1304.  
  1305.   }
  1306. /*
  1307. * OptionCheck()
  1308. *
  1309. * This function checks to see if all options fulfilled.
  1310. */
  1311. char OptionCheck(char mode)
  1312.   {
  1313.   long MsgTime;
  1314.   int  rover;
  1315.   if (mode == 1)
  1316.   return (char) (!Opt.LocalOnly && GetFirst(&Opt.Users) == NULL &&
  1317.   strLen(Opt.Phrase) == 0 && Opt.Date == -1l);
  1318.   /* else */
  1319.   /*
  1320.   * If any match failures, don't print.  printMessage(0) indicates a
  1321.   * a print with msg still on disk, while a (1) indicates message now in
  1322.   * the message buffer.
  1323.   */
  1324.   if (Opt.LocalOnly && msgBuf.mboname[0] &&
  1325.   strCmpU(msgBuf.mboname, cfg.codeBuf + cfg.nodeName) != SAMESTRING)
  1326.   return (char)FALSE;
  1327.   if (Opt.Date != -1l)
  1328.   if (ReadDate(msgBuf.mbdate, &MsgTime) != ERROR)
  1329.   if ((!revOrder && MsgTime < Opt.Date) ||
  1330.   (revOrder && MsgTime > Opt.Date))  return (char )FALSE;
  1331.   if (GetFirst(&Opt.Users) != NULL)
  1332.   if (SearchList(&Opt.Users, 0) == NULL) return NULL;
  1333.   if (strLen(Opt.Phrase) != 0)
  1334.     {
  1335.     getMsgStr(getMsgChar, msgBuf.mbtext, MAXTEXT);
  1336.     /* Kill extraneous line breaks */
  1337.     for (rover = 0; msgBuf.mbtext[rover]; rover++)
  1338.     if (msgBuf.mbtext[rover] == NEWLINE &&
  1339.     msgBuf.mbtext[rover + 1] != ' ' &&
  1340.     msgBuf.mbtext[rover + 1] != NEWLINE)
  1341.     msgBuf.mbtext[rover] = ' ';
  1342.     if (matchString(msgBuf.mbtext, Opt.Phrase, lbyte(msgBuf.mbtext))
  1343.     != NULL)
  1344.       {
  1345.       findMessage(msgBuf.mbheadSector, atol(msgBuf.mbId), TRUE);
  1346.       return (char)TRUE;
  1347.  
  1348.       }
  1349.     else return (char)FALSE;
  1350.  
  1351.     }
  1352.   return (char)TRUE;
  1353.  
  1354.   }
  1355. /*
  1356. * doDirectory()
  1357. *
  1358. * This function handles the read directory commands.
  1359. */
  1360. void doDirectory(char doDir, char *fileName, char *phrase)
  1361.   {
  1362.   #ifdef OLD_STYLE
  1363.   extern long BDSizeCount;
  1364.   int   FileCount;
  1365.   if (doDir)
  1366.     {
  1367.     FDSectCount     = 0;      /* global fDir() totals sectors in   */
  1368.     FileCount = wildCard(fDir, fileName, TRUE, phrase, TRUE);
  1369.     mPrintf("\n %d files, approximately %s sectors total\n ", FileCount,
  1370.     PrintPretty(FDSectCount, msgBuf.mbtext));
  1371.  
  1372.     }
  1373.   else
  1374.     {
  1375.     BDSizeCount = 0l;
  1376.     FileCount = wildCard(ShowVerbose, fileName, TRUE, phrase, TRUE);
  1377.     mPrintf("\n %d files, %s bytes total.\n ", FileCount,
  1378.     PrintPretty(BDSizeCount, msgBuf.mbtext));
  1379.  
  1380.     }
  1381.   #else
  1382.   int   FileCount;
  1383.   extern long FDSize;
  1384.   FDSize = 0l;
  1385.   FileCount = wildCard((doDir) ? fDir : ShowVerbose, fileName, TRUE, phrase,
  1386.   TRUE);
  1387.   mPrintf("\n %d files, ", FileCount);
  1388.   mPrintf((doDir) ? "approximately %s sectors total\n " :
  1389.   "%s bytes total.\n ",
  1390.   PrintPretty(FDSize, msgBuf.mbtext));
  1391.   #endif
  1392.   giveSpaceLeft(&roomBuf);
  1393.  
  1394.   }
  1395. #define MAX_USER_ERRORS 25
  1396. /*
  1397. * doRegular()
  1398. *
  1399. * The big fanout.
  1400. */
  1401. char doRegular(char x, char c)
  1402.   {
  1403.   static int errorCount = 0;
  1404.   char       toReturn, cc[2];
  1405.   SListBase  RegSelects =
  1406.     {
  1407.     NULL, FindSelect, NULL, NoFree, NULL
  1408.  
  1409.     };
  1410.   char *RegOpts[] =
  1411.     {
  1412.     TERM "Chat",    TERM "Door",       TERM "!", TERM "Enter",
  1413.     TERM "F\bRead", TERM "Goto",       TERM "+\bGoto",
  1414.     TERM "Read",    TERM "O\bRead",    TERM "N\bRead",
  1415.     TERM "Help",    TERM "Information",TERM "Known rooms",
  1416.     TERM "Login",   TERM "Skip",       TERM "Terminate",
  1417.     TERM "Backup",  TERM "Ungoto",     TERM "-\bBackup",
  1418.     TERM "QWK Mail",TERM "\\",         TERM ";",
  1419.     TERM "Z\bForget", TERM "?",
  1420.      " ",               " ",                ""
  1421.  
  1422.     };
  1423.   char       *legal = "CD!EFG+HIKLMNORSTBU-QZ";
  1424.   toReturn = GOOD_SELECT;
  1425.   if (loggedIn)
  1426.     {
  1427.     if (aide ||
  1428.     (strCmpU(logBuf.lbname, AskForNSMap(&Moderators, thisRoom))
  1429.     == SAMESTRING ||
  1430.     strCmpU(logBuf.lbname, FloorTab[thisFloor].FlModerator)
  1431.     == SAMESTRING))
  1432.     ExtraOption(RegOpts, TERM "Aide special fn:");
  1433.     if (!MeetDisabled)
  1434.       {
  1435.       ExtraOption(RegOpts, TERM "Meet User");
  1436.  
  1437.       }
  1438.     else ExtraOption(RegOpts, TERM "Moo!");
  1439.  
  1440.     }
  1441.  
  1442.    SpecialMessage("Status:User Idle");
  1443.  
  1444.   if (strchr(legal, c) != NULL) errorCount = 0;
  1445.   else        errorCount++;
  1446.   PushBack(c);  /* ugly kludge */
  1447.   if ((cc[0] = c) == 0 ||
  1448.   CmdMenuList(RegOpts, &RegSelects, NULL, cc, x, FALSE) == GOOD_SELECT)
  1449.     {
  1450.     switch (cc[0])
  1451.       {
  1452.       case 'C': toReturn = doChat(  x, '\0');     break;
  1453.       case '!':
  1454.       case 'D': toReturn = doDoor(  x);     break;
  1455.       case 'E': toReturn = doEnter( x, 'M' );     break;
  1456.       case 'F': toReturn = doRead(  x, 'F' );     break;
  1457.       case '+':
  1458.       case 'G': toReturn = doGoto(  x);     break;
  1459.       case 'H': toReturn = doHelp(  x);     break;
  1460.       case 'I': toReturn = doInfo();        break;
  1461.       case 'K': toReturn = doKnown( x);     break;
  1462.       case 'L': toReturn = doLogin( x);     break;
  1463.       case 'M': if (!MeetDisabled) toReturn = doMeet( x); break;
  1464.       case 'N': toReturn = doRead(  x, 'N' );     break;
  1465.       case 'O': toReturn = doRead(  x, 'O' );     break;
  1466.       case 'Q': toReturn = QWKmain();             break;
  1467.       case 'R': toReturn = doRead(  x, 'R' );     break;
  1468.       case 'S': toReturn = doSkip(  x);     break;
  1469.       case 'T': toReturn = doLogout(x, 'Q' );     break;
  1470.       case '-':
  1471.       case 'B': /* k2ne ism */
  1472.       case 'U': toReturn = doUngoto(x);     break;
  1473.       case '\'':
  1474.       case ';': toReturn = DoFloors();      break;
  1475.       case 0:
  1476.       pause(1);          /* To clear line noise */
  1477.       while (MIReady())   inp();   /* eat noise */
  1478.       if (newCarrier)
  1479.         {
  1480.         greeting();
  1481.         newCarrier  = FALSE;
  1482.  
  1483.         }
  1484.       if (justLostCarrier)
  1485.         {
  1486.         justLostCarrier = FALSE;
  1487.         terminate(TRUE, TRUE);
  1488.  
  1489.         }
  1490.       break;  /* irrelevant value */
  1491.       case '?':
  1492.       tutorial("mainopt.mnu", TRUE);
  1493.       if (whichIO == CONSOLE)   mPrintf("\n ^l: SysOp privileged fns\n ");
  1494.       break;
  1495.       case 'A': toReturn = doAide(x, 'E');      break;
  1496.       case 'Z': toReturn = doForget(x);     break;
  1497.       default:
  1498.       if (errorCount > MAX_USER_ERRORS)
  1499.         {
  1500.         logMessage(EVIL_SIGNAL, "", 'E');
  1501.         HangUp(TRUE);
  1502.  
  1503.         }
  1504.       toReturn=BAD_SELECT;
  1505.       break;
  1506.  
  1507.       }
  1508.  
  1509.     }
  1510.   if (toReturn == BACKED_OUT)
  1511.     {
  1512.     PushBack('\b');
  1513.     CmdMenuList(RegOpts, &RegSelects, NULL, cc, FALSE, FALSE);   /* does the BS */
  1514.  
  1515.     }
  1516.   KillList(&RegSelects);
  1517.   return  toReturn;
  1518.  
  1519.   }
  1520. /*
  1521. * doSkip()
  1522. *
  1523. * This function handles the <S>kip a room command.
  1524. */
  1525. char doSkip(char expand)
  1526.   {
  1527.   label roomName;     /* In case of ".Skip" */
  1528.   char  dispbuf[2 * NAMESIZE];
  1529.   int   rover;
  1530.   outFlag = IMPERVIOUS;
  1531.   sPrintf(dispbuf, "%s> goto ", roomTab[thisRoom].rtname);
  1532.   mPrintf("%s", dispbuf);
  1533.   if (expand)
  1534.     {
  1535.     if (getNormStr("", roomName, NAMESIZE, BS_VALID) == BACKED_OUT)
  1536.       {
  1537.       for (rover = 0; rover < strLen(dispbuf); rover++)
  1538.         {
  1539.         mPrintf("\b \b");
  1540.  
  1541.         }
  1542.       return BACKED_OUT;
  1543.  
  1544.       }
  1545.  
  1546.     }
  1547.   else
  1548.   roomName[0] = '\0';
  1549.   if (roomName[0] == '?')
  1550.   tutorial("skip.hlp", TRUE);
  1551.   else
  1552.     {
  1553.     roomTab[thisRoom].rtflags.SKIP = 1;     /* Set bit */
  1554.     gotoRoom(roomName, 'S');
  1555.  
  1556.     }
  1557.   return GOOD_SELECT;
  1558.  
  1559.   }
  1560. /*
  1561. * doSysop()
  1562. *
  1563. * This function handles the sysop-only menu.  It returns FALSE to fall
  1564. * invisibly into default error msg.
  1565. */
  1566. char doSysop()
  1567.   {
  1568.   extern unsigned long S_min, S_max;  /* stack tracking variables */
  1569.   extern char *NoFileStr;
  1570.   MSG_NUMBER  temp;
  1571.   int i;
  1572.   char  systemPW[200];
  1573.   extern char *VERSION, *LCHeld, *netVersion, *SysVers;
  1574.   extern int  fixVers, majorVers;
  1575.   logBuffer   lBuf;   /* This has to be local!  Don't sub logTmp */
  1576.   MenuId  id;
  1577.   char Priv[] = "\n Privileged Functions\n ";
  1578.   char  *CtdlOpts[] =
  1579.     {
  1580.     "A(bort)          ", "B(aud rate)           ", "C(hat mode)\n",
  1581.     "D(ebug mode)     ", "E(cho)                ", "F(ile grab)\n",
  1582.     "I(nformation)    ", "M(ODEM mode)          ", "N(et Menu)\n" ,
  1583.     "O(ther Commands) ", "R(einitialize Modem)  ", "Q(debug)\n",
  1584.     "U(ser Admin)     ", "X(exit from Citadel)\n",
  1585.     #ifdef NEED_MSG_PEEKING
  1586.     "Z ",
  1587.     #endif
  1588.     #ifdef NEED_MSG_LIST
  1589.     "Y ",
  1590.     #endif
  1591.     "1 ",    " W ",    "Z\n",    ""
  1592.  
  1593.     };
  1594.   if ((!onConsole || ConsolePassword) && !remoteSysop)
  1595.     {
  1596.     if (!(onConsole && ConsolePassword && strLen(cfg.sysPassword) == 0))
  1597.       {
  1598.       if ((!aide && !onConsole) || strLen(cfg.sysPassword) == 0)
  1599.         {
  1600.         return BAD_SELECT;
  1601.  
  1602.         }
  1603.       echo  = CALLER;
  1604.       getNormStr("SYSPWD", systemPW, sizeof systemPW, NO_ECHO);
  1605.       echo  = BOTH;
  1606.       if (strCmp(systemPW, cfg.sysPassword) != 0)
  1607.       return BAD_SELECT;
  1608.       remoteSysop = TRUE;
  1609.  
  1610.       }
  1611.  
  1612.     }
  1613.   initLogBuf(&lBuf);
  1614.  
  1615.    SpecialMessage("Status:***Sysop***");
  1616.  
  1617.   if (whichIO == CONSOLE && gotCarrier())
  1618.     Output_Citadel_Message("ONEMOM", NULL, NULL, NULL);
  1619.   id = RegisterSysopMenu("ctdlopt.mnu", CtdlOpts, Priv);
  1620.   while (onLine())
  1621.     {
  1622.     outFlag = OUTOK;
  1623.     SysopMenuPrompt(id, "\n privileged fn: ");
  1624.     switch (GetSysopMenuChar(id))
  1625.       {
  1626.       case 'W':
  1627.       EventShow();  /* Debug stuff */
  1628.       break;
  1629.       case '1':
  1630.       for (i = 0; i < MSGSPERRM; i++)
  1631.         {
  1632.         if (findMessage(roomBuf.msg[i].rbmsgLoc, roomBuf.msg[i].rbmsgNo,
  1633.         TRUE))
  1634.           {
  1635.           mPrintf("(%s : %s) ", msgBuf.mbsrcId, msgBuf.mboname);
  1636.  
  1637.           }
  1638.         mPrintf("%ld: %d\n ", roomBuf.msg[i].rbmsgNo,
  1639.         roomBuf.msg[i].rbmsgLoc);
  1640.  
  1641.         }
  1642.       break;
  1643.       #ifdef NEED_MSG_LIST
  1644.       case 'Y':
  1645.       CloseSysopMenu(id);
  1646.       for (i = 0; i < MSGSPERRM; i++)
  1647.         {
  1648.         mPrintf(" Room:%-20s:%ld: %d\n ",
  1649.         roomBuf.msg[i].rbname,
  1650.         roomBuf.msg[i].rbmsgNo,
  1651.         roomBuf.msg[i].rbmsgLoc);
  1652.         if( (i%20) == 19)iChar();
  1653.  
  1654.         };
  1655.       iChar();
  1656.       id = RegisterSysopMenu("ctdlopt.mnu",CtdlOpts,Priv);
  1657.       break;
  1658.       #endif
  1659.       #ifdef NEED_MSG_PEEKING
  1660.       case 'Z':
  1661.       CloseSysopMenu(id);
  1662.       mPeek();
  1663.       iChar();
  1664.       id = RegisterSysopMenu("ctdlopt.mnu", CtdlOpts,Priv);
  1665.       break;
  1666.       #endif
  1667.       case 'B':
  1668.       changeBauds(id);
  1669.       break;
  1670.       case 'E':
  1671.       sPrintf(systemPW, "%sabled\n ",
  1672.       (anyEcho = !anyEcho) ? "en" : "dis");
  1673.       ScrNewUser();
  1674.       SysopInfoReport(id, systemPW);
  1675.       break;
  1676.       case 'F':
  1677.       SysopRequestString(id, "EFILEN", systemPW, 50, 0);
  1678.       if (!ingestFile(systemPW, &tempMess))
  1679.         {
  1680.         char *fn;
  1681.         fn = strdup(systemPW);
  1682.         sPrintf(systemPW, NoFileStr, fn);
  1683.         SysopError(id, systemPW);
  1684.         free(fn);
  1685.  
  1686.         }
  1687.       break;
  1688.       case 'A':
  1689.       killLogBuf(&lBuf);
  1690.       CloseSysopMenu(id);
  1691.       return GOOD_SELECT;
  1692.       case 'C':
  1693.       cfg.BoolFlags.noChat =  (cfg.BoolFlags.noChat== 1) ? 0 : 1;
  1694.       sPrintf(systemPW, "%sabled\n ",cfg.BoolFlags.noChat ? "dis" : "en" );
  1695.       ScrNewUser();
  1696.       SysopInfoReport(id, systemPW);
  1697.       break;
  1698.       case 'D':
  1699.       cfg.BoolFlags.debug =  (cfg.BoolFlags.debug == 1) ? 0 : 1;
  1700.       sPrintf(systemPW, "%sabled\n ", cfg.BoolFlags.debug ? "en" : "dis");
  1701.       SysopInfoReport(id, systemPW);
  1702.       break;
  1703.       case 'I':
  1704.       sPrintf(msgBuf.mbtext, "\n %s V%s%s\n Net version %s",
  1705.       VARIANT_NAME, VERSION, SysVers, netVersion);
  1706.       sPrintf(lbyte(msgBuf.mbtext), "\n Commands version %d.%d    ", majorVers,
  1707.       fixVers);
  1708.       sPrintf(lbyte(msgBuf.mbtext), "ctdlcnfg.sys version %d\n ",
  1709.       cfg.paramVers);
  1710.       /* sPrintf(lbyte(msgBuf.mbtext), "coreleft is %ld\n ", coreleft()); */
  1711.       sPrintf(lbyte(msgBuf.mbtext), "Stack Usage: Min:%lx Max:%lx Size:%lx\n ",S_min,S_max,(S_max - S_min + 1));
  1712.       if( cfg.Audit != 0)sPrintf(lbyte(msgBuf.mbtext), "You are caller number %ld\n ",Get_Call_Count());
  1713.       sPrintf(lbyte(msgBuf.mbtext), "You have %s privledges\n ",Display_Privledges());
  1714.       ActiveEvents(msgBuf.mbtext);
  1715.       SysopDisplayInfo(id, msgBuf.mbtext, " Info ");
  1716.       break;
  1717.       case 'M':
  1718.       CloseSysopMenu(id);
  1719.       if (whichIO != MODEM)
  1720.         {
  1721.         whichIO = MODEM;
  1722.         setUp(FALSE);
  1723.  
  1724.         }
  1725.       printf("Chat mode %sabled\n ",
  1726.       cfg.BoolFlags.noChat  ?  "dis"  :  "en");
  1727.       if (!gotCarrier())
  1728.         {
  1729.         EnableModem(FALSE);
  1730.         ReInitModem();
  1731.  
  1732.         }
  1733.       #ifdef NEED_VISIBLE
  1734.       if (visibleMode) mPrintf("Visible mode on\n ");
  1735.       #endif
  1736.       killLogBuf(&lBuf);
  1737.       ScrNewUser();
  1738.       startTimer(NEXT_ANYNET);      /* start up anytime net timer */
  1739.       if (gotCarrier()) mPrintf("System on-line\n ");
  1740.       return GOOD_SELECT;
  1741.       case 'O':
  1742.       CloseSysopMenu(id);
  1743.       systemCommands();
  1744.       id = RegisterSysopMenu("ctdlopt.mnu", CtdlOpts,Priv);
  1745.       break;
  1746.       #ifdef MAKE_AVAILABLE
  1747.       case 'S':
  1748.       changeDate();
  1749.       break;
  1750.       #endif
  1751.       #ifdef NEED_VISIBLE
  1752.       case 'V':
  1753.       mPrintf(" VisibleMode==%d\n ",  visibleMode = !visibleMode);
  1754.       break;
  1755.       #endif
  1756.       case ERROR:
  1757.       case 'X':
  1758.       if (!SysopGetYesNo(id, NULL, "CONFRM")) break;
  1759.       ExitToMsdos = TRUE;
  1760.       exitValue   = (remoteSysop && !onConsole) ? REMOTE_SYSOP_EXIT : SYSOP_EXIT;
  1761.       CloseSysopMenu(id);
  1762.       return GOOD_SELECT;
  1763.       case 'N':
  1764.       CloseSysopMenu(id);
  1765.       netStuff();
  1766.       id = RegisterSysopMenu("ctdlopt.mnu", CtdlOpts, Priv);
  1767.       break;
  1768.       case 'R':
  1769.       if (gotCarrier()) HangUp(TRUE);
  1770.       Reinitialize();
  1771.       break;
  1772.       case 'Q':
  1773.       temp = SysopGetNumber(id, "SETOLD", 0l, 200000l);
  1774.       if (temp != 0l) cfg.oldest = temp;
  1775.       break;
  1776.       case 'U':
  1777.       CloseSysopMenu(id);
  1778.       UserAdmin(&lBuf);
  1779.       id = RegisterSysopMenu("ctdlopt.mnu", CtdlOpts,Priv);
  1780.       break;
  1781.  
  1782.       }
  1783.  
  1784.     }
  1785.   killLogBuf(&lBuf);
  1786.   CloseSysopMenu(id);
  1787.   return GOOD_SELECT;
  1788.  
  1789.   }
  1790. /*
  1791. * doUngoto()
  1792. *
  1793. * This function handles the Ungoto command.
  1794. */
  1795. char doUngoto(char moreYet)
  1796.   {
  1797.   label target;
  1798.   if (!moreYet)
  1799.     {
  1800.     strCpy(target, "");
  1801.  
  1802.     }
  1803.   else
  1804.     {
  1805.     if (getNormStr("", target, NAMESIZE, BS_VALID) == BACKED_OUT)
  1806.     return BACKED_OUT;
  1807.  
  1808.     }
  1809.   retRoom(target);
  1810.   return GOOD_SELECT;
  1811.  
  1812.   }
  1813. /*
  1814. * getCommand()
  1815. *
  1816. * This function prints the menu prompt and gets command char and returns a
  1817. * char via parameter and expand flag as value -- i.e., TRUE if parameters
  1818. * follow else FALSE.
  1819. */
  1820. char getCommand(char *c, char bs)
  1821.   {
  1822.   char expand, again;
  1823.   outFlag = OUTOK;
  1824.   if (!bs)
  1825.   givePrompt();
  1826.   do
  1827.     {
  1828.     again = FALSE;
  1829.     /* bizarre cheat */
  1830.     if (!bs)
  1831.       {
  1832.       if( justLostCarrier )
  1833.         {
  1834.         *c = 0;
  1835.  
  1836.         }
  1837.       else
  1838.         {
  1839.         *c = modIn();
  1840.         *c = toUpper(*c);
  1841.  
  1842.         };
  1843.  
  1844.       }
  1845.     else *c = '.';
  1846.     expand  = ( *c == ' ' || *c == '.' || *c == ',' || *c == '/' );
  1847.     if (expand)
  1848.       {
  1849.       if (!bs) oChar(*c);
  1850.       *c = modIn();
  1851.       if ((*c = toUpper(*c)) == '\b')
  1852.         {
  1853.         mPrintf("\b \b");
  1854.         again = TRUE;
  1855.  
  1856.         }
  1857.  
  1858.       }
  1859.     /* catch a late Pause, et al, command */
  1860.     else if (*c == 'P' || *c == '\b') again = TRUE;
  1861.     else if (*c == 7)
  1862.       {
  1863.       if( CheckForSpecial(13,69))netController(0,0,NO_NETS, ANY_CALL,0);
  1864.       }
  1865.     /* else oChar(*c); -- actually, handled somewhere else! */
  1866.     bs = FALSE;
  1867.  
  1868.     }
  1869.   while (again && onLine());
  1870.   if (justLostCarrier)
  1871.     {
  1872.     justLostCarrier = FALSE;
  1873.     terminate(TRUE, TRUE);
  1874.     expand = 0;
  1875.  
  1876.     }
  1877.   return expand;
  1878.  
  1879.   }
  1880. /*
  1881. * greeting()
  1882. *
  1883. * This gives system-entry blurb etc.
  1884. */
  1885. void greeting()
  1886.   {
  1887.   extern char *VERSION, *SysVers;
  1888.   extern int logTries;
  1889.   if (loggedIn) terminate(FALSE, TRUE);
  1890.   setUp(TRUE);     pause(10);
  1891.   logTries = 1; /* put this here instead of setUp() */
  1892.   memset(audit, ' ', AUDIT);
  1893.   acount = 0;
  1894.   PrintBanner = TRUE; /* signal for anytime net */
  1895.   doCR();
  1896.   expert = TRUE;
  1897.   HelpIfPresent("banner.pre");
  1898.   if (!MultiBanner("banner"))
  1899.   if (!HelpIfPresent("banner.blb"))
  1900.     Output_Citadel_Message("NODETL",NULL,NULL,NULL);
  1901.   HelpIfPresent("banner.sfx");
  1902.   expert = FALSE;
  1903.   Output_Citadel_Message("VERSIN",NULL,NULL,NULL);
  1904.   Output_Citadel_Message("HELPOP",NULL,NULL,NULL);
  1905.   printf("Chat mode %sabled\n", cfg.BoolFlags.noChat ? "dis" : "en");
  1906.   printf("\n 'MODEM' mode.\n "      );
  1907.   printf("(<ESC> for CONSOLE mode.)\n "   );
  1908.   while (MIReady())
  1909.   inp();
  1910.   gotoRoom(baseRoom, 'R');
  1911.   setUp(TRUE);
  1912.   PrintBanner = FALSE;
  1913.   if (outFlag == NET_CALL)
  1914.     {
  1915.     netController(0, 0, NO_NETS, ANY_CALL, 0);   /* so we don't call out */
  1916.  
  1917.     }
  1918.   else if (outFlag == STROLL_DETECTED)
  1919.     {
  1920.     StrollIt();
  1921.  
  1922.     }
  1923.   outFlag = OUTOK;
  1924.  
  1925.   }
  1926. /*
  1927. * main()
  1928. *
  1929. * This is the main manager.
  1930. */
  1931. void main(int argc, char **argv)
  1932.   {
  1933.   extern char logNetResults, netDebug, DisVandals,
  1934.   VortexHandle, BpsSet, *kip, ItlWxmodem, Zmodem, NoConsoleBanner;
  1935.   extern int  ParanoiaLimit, LD_Delay;
  1936.   extern long LowFree;
  1937.   char c, x, errMsg;
  1938.   int  CmdResult = GOOD_SELECT;
  1939.   cfg.weAre   = CITADEL;
  1940.   errMsg = FALSE;
  1941.   while (argc >= 2)
  1942.     {
  1943.     argc--;
  1944.     if (strCmpU(argv[argc], "+netlog") == SAMESTRING)
  1945.       {
  1946.       logNetResults = TRUE;
  1947.  
  1948.       }
  1949.     else if (strncmp(argv[argc], "kip=", 4) == SAMESTRING)
  1950.       {
  1951.       kip = argv[argc] + 4;
  1952.  
  1953.       }
  1954.     else if (strncmp(argv[argc], "lowfree=", 8) == SAMESTRING)
  1955.       {
  1956.       LowFree = atoi(argv[argc] + 8);
  1957.  
  1958.       }
  1959.     else if (strncmp(argv[argc], "lddelay=", 8) == SAMESTRING)
  1960.       {
  1961.       LD_Delay = atoi(argv[argc] + 8);
  1962.  
  1963.       }
  1964.     else if (strncmp(argv[argc], "paranoia=", 9) == SAMESTRING)
  1965.       {
  1966.       if ((ParanoiaLimit = atoi(argv[argc] + 9)) < 1)
  1967.       ParanoiaLimit = 10000;
  1968.  
  1969.       }
  1970.     else if (strncmp(argv[argc], "bps=", 4) == SAMESTRING)
  1971.       {
  1972.       BpsSet = TRUE;
  1973.       ReadBps(argv[argc]);
  1974.  
  1975.       }
  1976.     else if (strCmpU(argv[argc], "+netdebug") == SAMESTRING)
  1977.       {
  1978.       netDebug = TRUE;
  1979.  
  1980.       }
  1981.     else if (strCmpU(argv[argc], "+nochat") == SAMESTRING)
  1982.       {
  1983.       NoChatAtAll = TRUE;
  1984.  
  1985.       }
  1986.     else if (strCmpU(argv[argc], "+nomeet") == SAMESTRING)
  1987.       {
  1988.       MeetDisabled = TRUE;
  1989.  
  1990.       }
  1991.     else if (strCmpU(argv[argc], "+noecho") == SAMESTRING)
  1992.       {
  1993.       anyEcho = FALSE;
  1994.  
  1995.       }
  1996.     else if (strCmpU(argv[argc], "+wx") == SAMESTRING)
  1997.       {
  1998.       #ifdef WXMODEM_AVAILABLE
  1999.       ItlWxmodem = TRUE;
  2000.       #endif
  2001.  
  2002.       }
  2003.     else if (strCmpU(argv[argc], "+vortex") == SAMESTRING)
  2004.       {
  2005.       VortexHandle = TRUE;
  2006.  
  2007.       }
  2008.     else if (strCmpU(argv[argc], "-vortex") == SAMESTRING)
  2009.       {
  2010.       VortexHandle = FALSE;
  2011.  
  2012.       }
  2013.     else if (strCmpU(argv[argc], "+vandaloff") == SAMESTRING)
  2014.       {
  2015.       DisVandals = TRUE;
  2016.  
  2017.       }
  2018.     else if (strCmpU(argv[argc], "+conpwd") == SAMESTRING)
  2019.       {
  2020.       ConsolePassword = TRUE;
  2021.  
  2022.       }
  2023.     else if (strCmpU(argv[argc], "+noconban") == SAMESTRING)
  2024.       {
  2025.       NoConsoleBanner = TRUE;
  2026.  
  2027.       }
  2028.     else if (strncmp(argv[argc], "zmodem=", 7) == SAMESTRING)
  2029.       {
  2030.       Zmodem = argv[argc][7];
  2031.  
  2032.       }
  2033.     else
  2034.       {
  2035.       printf("Invalid  argument: %s\n", argv[argc]);
  2036.       errMsg = TRUE;
  2037.  
  2038.       }
  2039.  
  2040.     }
  2041.   if (initCitadel())
  2042.     {
  2043.     greeting();
  2044.     logMessage(FIRST_IN, "", FALSE);
  2045.  
  2046.     }
  2047.   startTimer(NEXT_ANYNET);      /* start anytime net timer */
  2048.   if (errMsg)
  2049.     {
  2050.     sPrintf(msgBuf.mbtext, "System brought up from apparent crash.");
  2051.     aideMessage(NULL,FALSE);
  2052.  
  2053.     }
  2054.   while (!ExitToMsdos)
  2055.     {
  2056.     x       = getCommand(&c, (CmdResult == BACKED_OUT));
  2057.     outFlag = OUTOK;
  2058.     CmdResult = (c==CNTRLl)  ?  doSysop() : doRegular(x, c);
  2059.     if (CmdResult == BAD_SELECT)
  2060.       {
  2061.       Output_Citadel_Message("HLPMNU",NULL,NULL,NULL);
  2062.       }
  2063.  
  2064.     }
  2065.   if (loggedIn)
  2066.   terminate( /* hangUp == */ exitValue == DOOR_EXIT ? FALSE : TRUE, TRUE);
  2067.   logMessage(exitValue != DOOR_EXIT ? LAST_OUT : DOOR_OUT , "", FALSE);
  2068.   writeSysTab();
  2069.   if (onConsole) EnableModem(FALSE);  /* just in case... */
  2070.   if (exitValue != DOOR_EXIT && !cfg.BoolFlags.IsDoor) DisableModem(TRUE);
  2071.   ModemShutdown(((exitValue == DOOR_EXIT || cfg.BoolFlags.IsDoor) && !onConsole) ? FALSE : TRUE);
  2072.   systemShutdown(0);
  2073.   exit(exitValue);
  2074.  
  2075.   }
  2076. /*
  2077. * UserAdmin()
  2078. *
  2079. * This function handles the user administration menu.
  2080. */
  2081. void UserAdmin(logBuffer *lBuf)
  2082.   {
  2083.   extern SListBase MailForward;
  2084.   int      logNo, ltabSlot, result;
  2085.   SYS_FILE killHeld;
  2086.   label    who;
  2087.   MenuId   id;
  2088.   char User_Prompt[] = "\nUser Administration\n ";
  2089.   char     *UserOpts[] =
  2090.     {
  2091.     "A(dd new user)     ", "D(oor privs)  ", "E(ndless User)\n",
  2092.     "F(ile privs)       ", "K(ill user)   ", "N(et privs)\n",
  2093.     "P(rivileges-aide)  ", "T(wit)        ", "X(eXit)\n",
  2094.     ""
  2095.  
  2096.     };
  2097.   id = RegisterSysopMenu("useropt.mnu", UserOpts, User_Prompt);
  2098.   while (onLine())
  2099.     {
  2100.     outFlag = OUTOK;
  2101.     SysopMenuPrompt(id, "\n user admin fn: ");
  2102.     switch (GetSysopMenuChar(id))
  2103.       {
  2104.       case ERROR:
  2105.       case 'X': CloseSysopMenu(id); return ;
  2106.       case 'E': /* permanent account administration */
  2107.       if ((logNo = GetUser(who, lBuf, TRUE)) == ERROR ||
  2108.       logNo == cfg.MAXLOGTAB) break;
  2109.       Output_Citadel_Message((lBuf->lbflags.PERMANENT ? "NPERMA" : "PERMAC")
  2110.                             ,(long)lBuf->lbname,NULL,NULL);
  2111.       if (!SysopGetYesNo(id, NULL, "CONFRM"))   break;
  2112.       lBuf->lbflags.PERMANENT = !lBuf->lbflags.PERMANENT;
  2113.       putLog(lBuf, logNo);
  2114.       /* find position in logTab[] and update that, too */
  2115.       if ((ltabSlot = PWSlot(lBuf->lbpw, /* load == */ FALSE)) != ERROR)
  2116.       logTab[ltabSlot].ltpermanent = lBuf->lbflags.PERMANENT;
  2117.       if (loggedIn  &&  strCmpU(logBuf.lbname, who)==SAMESTRING)
  2118.       logBuf.lbflags.PERMANENT = lBuf->lbflags.PERMANENT;
  2119.       break;
  2120.       case 'T':
  2121.       if ((logNo = GetUser(who, lBuf, TRUE)) == ERROR ||
  2122.       logNo == cfg.MAXLOGTAB) break;
  2123.  
  2124.       Output_Citadel_Message((lBuf->lbflags.TWIT ? "TWITST" : "TWITNT")
  2125.                             ,(long)lBuf->lbname,NULL,NULL);
  2126.       if (!SysopGetYesNo(id, NULL, "CONFRM"))   break;
  2127.  
  2128.       lBuf->lbflags.TWIT = !lBuf->lbflags.TWIT;
  2129.  
  2130.       putLog(lBuf, logNo);
  2131.       if (loggedIn  &&  strCmpU(logBuf.lbname, who)==SAMESTRING)
  2132.       logBuf.lbflags.TWIT = lBuf->lbflags.TWIT;
  2133.       break;
  2134.       case 'F':
  2135.       if ((logNo = GetUser(who, lBuf, TRUE)) == ERROR) break;
  2136.       if (logNo == cfg.MAXLOGTAB)
  2137.         {
  2138.         result = DoAllQuestion("GVFLPR","TAFLPR");
  2139.         if (result == ERROR) break;
  2140.         for (logNo = 0; logNo < cfg.MAXLOGTAB; logNo++)
  2141.           {
  2142.           getLog(lBuf, logNo);
  2143.           if (!onConsole) mPrintf(".");
  2144.           if (lBuf->lbflags.L_INUSE && lBuf->lbflags.DL_PRIVS != result)
  2145.             {
  2146.             lBuf->lbflags.DL_PRIVS = result;
  2147.             putLog(lBuf, logNo);
  2148.  
  2149.             }
  2150.  
  2151.           }
  2152.         break;
  2153.  
  2154.         }
  2155.       Output_Citadel_Message((lBuf->lbflags.DL_PRIVS ? "NFLPRI" : "FILPRI")
  2156.                             ,(long)lBuf->lbname,NULL,NULL);
  2157.       if (!SysopGetYesNo(id, NULL, "CONFRM"))   break;
  2158.  
  2159.       lBuf->lbflags.DL_PRIVS = !lBuf->lbflags.DL_PRIVS;
  2160.       putLog(lBuf, logNo);
  2161.       if (loggedIn  &&  strCmpU(logBuf.lbname, who)==SAMESTRING)
  2162.       logBuf.lbflags.DL_PRIVS = lBuf->lbflags.DL_PRIVS;
  2163.       break;
  2164.       case 'K':
  2165.       if ((logNo = GetUser(who, lBuf, TRUE)) == ERROR ||
  2166.       logNo == cfg.MAXLOGTAB) break;
  2167.       Output_Citadel_Message( "KILLTH",(long)lBuf->lbname,lBuf->credit,NULL);
  2168.       if (!SysopGetYesNo(id, NULL, "CONFRM"))   break;
  2169.       ltabSlot = PWSlot(lBuf->lbpw, /* load == */ FALSE);
  2170.       lBuf->lbname[0] = '\0';
  2171.       lBuf->lbpw[0  ] = '\0';
  2172.       lBuf->lbflags.L_INUSE = FALSE;
  2173.       putLog(lBuf, logNo);
  2174.       logTab[ltabSlot].ltpwhash       = 0;
  2175.       logTab[ltabSlot].ltnmhash       = 0;
  2176.       if (cfg.BoolFlags.HoldOnLost)
  2177.         {
  2178.         sPrintf(msgBuf.mbtext, LCHeld, logNo);
  2179.         makeSysName(killHeld, msgBuf.mbtext, &cfg.holdArea);
  2180.         unlink(killHeld);
  2181.  
  2182.         }
  2183.       KillData(&MailForward, who);
  2184.       UpdateForwarding();
  2185.       break;
  2186.       case 'P':
  2187.       if ((logNo = GetUser(who, lBuf, TRUE)) == ERROR ||
  2188.       logNo == cfg.MAXLOGTAB) break;
  2189.       if (lBuf->lbflags.AIDE == 1)
  2190.         {
  2191.         lBuf->lbflags.AIDE = 0;
  2192.         lBuf->lbgen[AIDEROOM] = ((roomTab[AIDEROOM].rtgen-1) % MAXGEN)
  2193.         << GENSHIFT;
  2194.  
  2195.         }
  2196.       else
  2197.         {
  2198.         lBuf->lbflags.AIDE = 1;
  2199.         lBuf->lbgen[AIDEROOM] = roomTab[AIDEROOM].rtgen << GENSHIFT;
  2200.         lBuf->lbgen[AIDEROOM] += MAXVISIT-1;
  2201.  
  2202.         }
  2203.       Output_Citadel_Message((lBuf->lbflags.AIDE ? "AIDPRI" : "NADPRI" )
  2204.                             ,(long)lBuf->lbname,NULL,NULL);
  2205.       if (!SysopGetYesNo(id, NULL, "CONFRM"))   break;
  2206.       putLog(lBuf, logNo);
  2207.       /* see if it is us: */
  2208.       if (loggedIn  &&  strCmpU(logBuf.lbname, who)==SAMESTRING)
  2209.         {
  2210.         aide = (lBuf->lbflags.AIDE == 1) ? TRUE : FALSE;
  2211.         logBuf.lbgen[AIDEROOM] = lBuf->lbgen[AIDEROOM];
  2212.  
  2213.         }
  2214.       break;
  2215.       case 'D':
  2216.       if ((logNo = GetUser(who, lBuf, TRUE)) == ERROR) break;
  2217.       if (logNo == cfg.MAXLOGTAB)
  2218.         {
  2219.         result = DoAllQuestion("GVDRPR","TADRPR");
  2220.         if (result == ERROR) break;
  2221.         for (logNo = 0; logNo < cfg.MAXLOGTAB; logNo++)
  2222.           {
  2223.           getLog(lBuf, logNo);
  2224.           if (!onConsole) mPrintf(".");
  2225.           if (lBuf->lbflags.L_INUSE && lBuf->lbflags.DOOR_PRIVS != result)
  2226.             {
  2227.             lBuf->lbflags.DOOR_PRIVS = result;
  2228.             putLog(lBuf, logNo);
  2229.  
  2230.             }
  2231.  
  2232.           }
  2233.         break;
  2234.  
  2235.         }
  2236.       lBuf->lbflags.DOOR_PRIVS  = (lBuf->lbflags.DOOR_PRIVS == 1) ? 0 : 1;
  2237.       Output_Citadel_Message((lBuf->lbflags.DOOR_PRIVS ? "DORPRI" : "NDRPRI")
  2238.                             ,(long)lBuf->lbname,NULL,NULL);
  2239.       if (!SysopGetYesNo(id, NULL, "CONFRM"))   break;
  2240.  
  2241.       putLog(lBuf, logNo);
  2242.       /* see if it is us: */
  2243.       if (loggedIn  &&  strCmpU(logBuf.lbname, who)==SAMESTRING)
  2244.         {
  2245.         DoorPriv = lBuf->lbflags.DOOR_PRIVS;
  2246.  
  2247.         }
  2248.       break;
  2249.       case 'N':
  2250.       NetPrivs(who);
  2251.       break;
  2252.       case 'A':
  2253.       CloseSysopMenu(id);
  2254.       newUser(&logTmp);
  2255.       id = RegisterSysopMenu("useropt.mnu", UserOpts, User_Prompt);
  2256.       break;
  2257.  
  2258.       }
  2259.  
  2260.     }
  2261.  
  2262.   }
  2263.